/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       luck_object.cpp

	$Header: /game/luck_object.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "luck_object.h"

#include "adv_object_type.h"
#include "adventure_frame.h"
#include "adventure_sounds.h"
#include "ai_value.h"
#include "army.h"
#include "basic_dialog.h"
#include "creature_array.h"
#include "external_string.h"
#include "mouse_event.h"
#include "music.h"
#include "object_registration.h"
#include "player.h"
#include "random.h"
#include "simple_dialog.h"

namespace
{
	// --------------------------------------------------------------
	// create a luck object
	// --------------------------------------------------------------
	template <class t_type>
	class t_bonus_factory : public t_object_factory_base
	{
	public:
		t_bonus_factory( int bonus );

		virtual t_object* create( std::string const& name, t_object_type const& type ) const;
	protected:
		int m_bonus;
	};

	template <class t_type>
	inline t_bonus_factory<t_type>::t_bonus_factory( int bonus )
	{
		m_bonus = bonus;
	}

	template <class t_type>
	t_stationary_adventure_object* 
	t_bonus_factory<t_type>::create( std::string const&		name, 
									 t_object_type const&	type ) const
	{
		return new t_type( name, m_bonus );
	}

	// --------------------------------------------------------------
	// create a luck object
	// --------------------------------------------------------------
	template <class t_type>
	class t_register_object : public t_object_registration_base
	{
	public:
		t_register_object( int amount, t_adv_object_type type );
		t_register_object( int amount, t_adv_object_type type, int major_subtype ); 
		t_register_object( int amount, t_adv_object_type type, int major_subtype, 
			             int minor_subtype ); 
	protected:
		t_bonus_factory<t_type> m_factory;
	};

	template <class t_type>
	inline t_register_object<t_type>::t_register_object( int amount, t_adv_object_type type )
		           : t_object_registration_base( type, &m_factory ), m_factory( amount )
	{
	}

	template <class t_type>
	inline t_register_object<t_type>::t_register_object( int amount, t_adv_object_type type, int major_subtype ) 
		           : t_object_registration_base( type, major_subtype, &m_factory ), 
					 m_factory( amount )
	{
	}
	
	template <class t_type>
	inline t_register_object<t_type>::t_register_object( int amount, t_adv_object_type type, int major_subtype, 
			             int minor_subtype ) 
		           : t_object_registration_base( type, major_subtype, minor_subtype,
					                             &m_factory ), m_factory( amount )
	{
	}

	typedef t_register_object<t_luck_object> t_register_luck;
	typedef t_register_object<t_morale_object> t_register_morale;

	static t_register_luck k_register_oyster( 1, k_adv_object_oyster );
	static t_register_luck k_register_colver_field( 1, k_adv_object_clover_field );
	static t_register_luck k_register_dolphin( 2, k_adv_object_dolphin_school );
	static t_register_luck k_register_faerie( 1, k_adv_object_faerie_ring );
	static t_register_luck k_register_fountain( 1, k_adv_object_fountain, 
		                                           k_fountain_of_fortune );
	static t_register_luck k_register_luck( 2, k_adv_object_rainbow );

	static t_register_morale k_register_bouy( 1, k_adv_object_buoy );
	static t_register_morale k_register_youth( 1, k_adv_object_fountain, 
		                                           k_fountain_of_youth );

	static t_object_registration<t_adv_blattner_stone> 
		   k_blattner_registration( k_adv_object_blattner_stone);

	static t_object_registration<t_adv_idol_of_fortune> 
           k_register_idol( k_adv_object_idol_of_fortune );

};

// --------------------------------------------------------------
// object which gives a temporary boost to luck
// --------------------------------------------------------------
t_luck_object::t_luck_object( t_stationary_adventure_object const& source, int bonus )
             : t_stationary_adventure_object( source )
{
	m_bonus = bonus;
}

// --------------------------------------------------------------
// object which gives a temporary boost to luck
// --------------------------------------------------------------
void t_luck_object::add_bonus( t_creature_stack& creature )
{
	creature.add_bonus( k_stat_luck, m_bonus, get_type() );
}

// --------------------------------------------------------------
// object which gives a temporary boost to luck
// --------------------------------------------------------------
void t_luck_object::add_icons( t_basic_dialog* dialog )
{
	dialog->add_luck( m_bonus );
}

// --------------------------------------------------------------
// object which gives a temporary boost to luck
// --------------------------------------------------------------
void t_luck_object::activate_trigger( t_army* army, t_adv_map_point const& point, 
		                              t_direction direction, t_adventure_frame* frame )
{
	int  i;
	bool any_award = false;

	// loop through all heroes/creatures in the army and award temporary statistic based on subtype

	t_creature_array& creatures = army->get_creatures();


	for (i = 0; i < t_creature_array::k_size; i++)
	{
		if (creatures[i].get_number() == 0)
			continue;
		if (creatures[i].has_temporary_bonus( get_type() ))
			continue;
		add_bonus( creatures[i] );
		any_award = true;
	}

	// determine what response to print
	if (army->get_owner()->is_computer())
		return;

	t_basic_dialog*          dialog;
	std::string              text;

	dialog = new t_basic_dialog;
	if (any_award)
	{
		text = get_text( "initial" );
		add_icons( dialog );
	}
	else
	{
		text = get_text( "empty" );
	}

	dialog->set_text( text );
	dialog->add_ok_button();
	dialog->set_title( get_name() );
	dialog->open( get_dialog_bottom( point ), true, k_align_bottom );
	t_sound_cache music = get_music_playing();
	stop_music();
	get_dialog_sound( k_dialog_sound_luck )->play( get_sound_volume() );
	dialog->run_modal();
    // Update stats.
    frame->update_army();
	play_music( music );
}

// --------------------------------------------------------------
// object which gives a temporary boost to luck
// --------------------------------------------------------------
bool t_luck_object::visited( t_army const* army ) const
{
	if (army == 0)
		return false;

	t_creature_array const& creatures = army->get_creatures();
	int                     i;

	for (i = 0; i < t_creature_array::k_size; i++)
	{
		if (creatures[i].get_number() == 0)
			continue;
		if (creatures[i].has_temporary_bonus( get_type() ))
			continue;
		return false;
	}
	return true;
}

float t_luck_object::ai_value(t_adventure_ai const& ai, t_creature_array const& army, int move_cost) const
{
	return ai_value_of_luck_change( army, get_type(), m_bonus );
}

// --------------------------------------------------------------
// object which gives a temporary boost to luck
// --------------------------------------------------------------
extern t_external_string const k_text_no_benefit;

std::string t_luck_object::get_balloon_help() const
{
	t_adventure_frame*   adventure_frame = get_adventure_frame();
	t_army*              army = adventure_frame->get_selected_army();

	if (visited(army))
	{
		std::string result;

		result = get_name();
		result += "\n";
		result += k_text_no_benefit;
		return result;
	}
	return get_name();
}

// --------------------------------------------------------------
// object which gives a temporary boost to luck
// --------------------------------------------------------------
int	t_luck_object::get_version() const
{
	return 1;
}

// --------------------------------------------------------------
// object which gives a temporary boost to luck
// --------------------------------------------------------------
bool t_luck_object::read( std::streambuf&						stream, 
						  t_qualified_adv_object_type const&	type,
						  int									version )
{
	if (version < 1)
		m_bonus = 1;
	else
		m_bonus = get<t_uint8>( stream );
	return true;
}

// --------------------------------------------------------------
// object which gives a temporary boost to luck
// --------------------------------------------------------------
void t_luck_object::right_click( t_mouse_event const& event,
								 t_adventure_frame* adventure_frame )
{
	t_army*     army = adventure_frame->get_selected_army();
	std::string text;

	if (visited(army))
		text = get_text( "help.empty" );
	else
		text = get_text( "help" );
	show_popup_text( text, event.screen_point );
}

// --------------------------------------------------------------
// object which gives a temporary boost to luck
// --------------------------------------------------------------
bool t_luck_object::write( std::streambuf& stream ) const
{
	put<t_uint8>( stream, m_bonus );
	return true;
}

// --------------------------------------------------------------
// object which gives a temporary boost to morale
// --------------------------------------------------------------
void t_morale_object::add_bonus( t_creature_stack& creature )
{
	creature.add_bonus( k_stat_morale, m_bonus, get_type() );
}

void t_morale_object::add_icons( t_basic_dialog* dialog )
{
	dialog->add_morale( m_bonus );
}

float t_morale_object::ai_value( t_adventure_ai const& ai, t_creature_array const& army, int move_cost ) const
{
	return ai_value_of_morale_change( army, get_type(), m_bonus );
}

// --------------------------------------------------------------
// object which gives a temporary boost to morale and luck
// --------------------------------------------------------------
void t_adv_blattner_stone::add_bonus( t_creature_stack& creature )
{
	creature.add_bonus( k_stat_morale, m_bonus, get_type() );
	creature.add_bonus( k_stat_luck, m_bonus, get_type() );
}

void t_adv_blattner_stone::add_icons( t_basic_dialog* dialog )
{
	dialog->add_morale( m_bonus );
	dialog->add_luck( m_bonus );
}

float t_adv_blattner_stone::ai_value( t_adventure_ai const& ai, t_creature_array const& army, int move_cost ) const
{
	return ai_value_of_morale_change( army, get_type(), m_bonus) + ai_value_of_luck_change( army, get_type(), m_bonus);
}

// -------------------------------------------------------
// object which gives either +1 luck or +1 morale
// -------------------------------------------------------
void t_adv_idol_of_fortune::activate_trigger( t_army* army, t_adv_map_point const& point, 
		                                      t_direction direction, t_adventure_frame* frame )
{
	m_give_luck = (random(2) == 1);
	t_luck_object::activate_trigger( army, point, direction, frame );
}

void t_adv_idol_of_fortune::add_bonus( t_creature_stack& creature )
{
	if (m_give_luck)
		creature.add_bonus( k_stat_luck, m_bonus, get_type() );
	else
		creature.add_bonus( k_stat_morale, m_bonus, get_type() );
}

void t_adv_idol_of_fortune::add_icons( t_basic_dialog* dialog )
{
	if (m_give_luck)
		dialog->add_luck( m_bonus );
	else
		dialog->add_morale( m_bonus );
}

float t_adv_idol_of_fortune::ai_value( t_adventure_ai const& ai, t_creature_array const& army, int move_cost ) const
{
	return ( ai_value_of_luck_change( army, get_type(), m_bonus )
				+ ai_value_of_morale_change( army, get_type(), m_bonus ) ) / 2.0f;
}
